#include "engine.h"
Engine::Engine(QObject *parent) :QObject(parent){
    qRegisterMetaType<QVector<double>>("QVector<double>");
}

void Engine::init(){
    jumpToStart();
    bool ret = initLUSolver();
    m_prepared = ret;
    QString output = ret?"初始化成功":"初始化失败，请检查参数";
    qDebug()<<output;
    emit prepared(ret);
}

void Engine::jumpToStart(){
    int rows = m_parm.yNums;int cols = m_parm.xNums;
    if(rows*cols<=0){
        return ;
    }
    m_currentStep = 1;
    m_tFirst.resize(rows*cols);
    m_tSecond.resize(rows*cols);
    m_tFirst.fill(m_parm.t0);
    m_tSecond.fill(m_parm.t0);
    auto mat = MatrixXd::Map(&m_tFirst[0],rows,cols);
    mat.row(0).fill(m_parm.tw);
    mat.row(rows-1).fill(m_parm.tw);
    mat.col(0).fill(m_parm.tw);
    mat.col(cols-1).fill(m_parm.tw);
}

bool Engine::initLUSolver(){
    int rows = m_parm.yNums;int cols = m_parm.xNums;
    double onePlusTwoR=1+2*(m_parm.rx+m_parm.ry);
    MatrixXd A(MatrixXd::Identity(rows*cols,rows*cols));
    for(int j=2;j<rows;j++){
        for(int i=2;i<cols;i++){
            int index = indexOf(i,j,cols);
            A(index,index) = onePlusTwoR;
            A(index,indexOf(i-1,j,cols)) = -m_parm.rx;
            A(index,indexOf(i+1,j,cols)) = -m_parm.rx;
            A(index,indexOf(i,j-1,cols)) = -m_parm.ry;
            A(index,indexOf(i,j+1,cols)) = -m_parm.ry;
        }
    }
    m_lu.compute(A.sparseView());
    return m_lu.info()==Success;
}

void Engine::next(){
    if(!m_prepared){
        qDebug()<<"错误：未初始化，还不能进行计算";
        emit finished(false);
        return;
    }
    if(m_currentStep>m_parm.stop){
        qDebug()<<"计算完成。";
        emit finished(true);
        return;
    }
    m_tSecond = m_lu.solve(m_tFirst);
    m_tFirst = m_tSecond;
    copyToQVector(m_tSecond,m_cache);
    emit stepFinished(m_lu.info()==Success,m_currentStep,m_cache);
    m_currentStep ++;
}


void Engine::setParameter(Parameter parm){
    m_parm = parm;
}

void Engine::unInit(){
    m_prepared = false;
    emit prepared(false);
}

void Engine::prepare(bool ok){
    if(ok){
        init();
    }else{
        unInit();
    }
}

void Engine::copyToQVector(const VectorXd vec, QVector<double> & qvec){
    qvec.clear();
    if (vec.rows()!=qvec.size()){
        qvec.resize(vec.rows());
    }
    VectorXd::Map(&(qvec[0]),qvec.size()) = vec;
}
